package com.ttxs.fileformathandling.utils;

import com.alibaba.fastjson2.*;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ttxs.fileformathandling.common.ErrorCode;
import com.ttxs.fileformathandling.exception.BusinessException;
import org.apache.commons.text.StringEscapeUtils;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.util.Map;
import java.util.regex.Pattern;

/**
 * JSON工具类   格式转换、格式验证、格式化功能
 *
 * @author cwt
 */
public class JsonUtils {

    private static void begin(String url) {
        if (!jsonValidator(url)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "JSON文件格式错误");
        }
    }

    public static String jsonCompress(String jsonString) {
        Object obj = JSON.parse(jsonString);
        //这里JSONWriter.Feature.WriteNulls将属性值为空的也写入json
        return JSON.toJSONString(obj, JSONWriter.Feature.WriteNulls);
    }


    /***
     *判断json字符串|文件是否合法
     * @param url 指定文件的地址
     * @return json的格式是否合法
     * @author cwt
     */

    public static boolean jsonValidator(String url) {
        String jsonString = FileUtils.readFileToString(url, "UTF-8");
        try {
            ObjectMapper mapper = new ObjectMapper();
            //双重校验
            mapper.readTree(jsonString); //jackson校验
            JSON.parse(jsonString);  // fastjson校验
            return true; // JSON格式有效
        } catch (JsonParseException e) {
            // JSON格式无效
            return false;
        } catch (Exception e) {
            // 其他异常
            return false;
        }
    }


    public static String jsonFormatter(String url) {
        begin(url);
        String jsonString = FileUtils.readFileToString(url, "UTF-8");
        Object obj = JSON.parse(jsonString);
        return JSON.toJSONString(obj, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.WriteNulls);
    }

    /***
     *实现JSON转XML
     * @param url 文件地址
     * @param root root标签
     * @param gt 分隔符
     * @return 返回转化好的xml字符串
     * @author cwt
     */

    public static String json2Xml(String url, String root, String gt) {
        begin(url);
        String jsonString = FileUtils.readFileToString(url, "UTF-8");
        String content;
        //将读取的文件内容转成 JSONObject对象
        if (jsonString.startsWith("[")) {   //fastjson对[开头的json文件读取异常
            content = analyzeJson2Xml(JSONArray.parseArray(jsonString), gt);
        } else {
            content = analyzeJson2Xml(JSON.parseObject(jsonString), gt);
        }
        if (root == null || "".equals(root)) {
            root = "root";
        }
        //加入表示头标签
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<" + root + ">\n" + content + "</" + root + ">";
    }


    public static String json2Xml(String jsonString, String root) {
        ;
        String content;
        //将读取的文件内容转成 JSONObject对象
        if (jsonString.startsWith("[")) {   //fastjson对[开头的json文件读取异常
            content = analyzeJson2Xml(JSONArray.parseArray(jsonString), "\t");
        } else {
            content = analyzeJson2Xml(JSON.parseObject(jsonString), "\t");
        }
        if (root == null || "".equals(root)) {
            root = "root";
        }
        //加入表示头标签
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<" + root + ">\n" + content + "</" + root + ">";
    }

    /***
     * 实现JSON转为CSV
     * @param url 源文件地址
     * @param gt 分隔符
     * @author cwt
     */

    public static String json2Csv(String url, String gt) {
        begin(url);
        String jsonString; // 接收JSON文件内容
        StringBuilder csvStr = new StringBuilder();
        jsonString = FileUtils.readFileToString(url, "UTF-8");
        //直接转成数组 在json转csv中  一般json都以[]开头结尾
        JSONArray jsonArray;
        try {
            jsonArray = JSONArray.parseArray(jsonString);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "该json文件无法转为csv文件");
        }

        // 写入CSV表头 由于CSV文件的特殊性，JSON中以数组形式表现
        //取出第一组数据，提取表头
        JSONObject firstObject = jsonArray.getJSONObject(0);
        StringBuilder headerBuilder = new StringBuilder();

        for (String key : firstObject.keySet()) {
            headerBuilder.append(key).append(gt);

        }
        //将去除最后一个多余的 ,
        headerBuilder.deleteCharAt(headerBuilder.length() - 1);
        csvStr.append(headerBuilder).append("\n");

        // 写入CSV数据
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            StringBuilder lineBuilder = new StringBuilder();
            for (String key : jsonObject.keySet()) {
//给csv文件，如果值是字符串则加上双引号
//                int flag = 0;
//                String val = jsonObject.getString(key);
//                try {
//                    Double.parseDouble(val);
//                } catch (NumberFormatException e1) {
//                    flag = 1;
//                }
//                if ("true".equalsIgnoreCase(val)||"false".equalsIgnoreCase(val)) {
//                    flag = 0;
//                }
//                if (flag == 1) {
//                    lineBuilder.append("\"");
//                }
//                //获取对应key的值
//                lineBuilder.append(val);
//                if (flag == 1) {
//                    lineBuilder.append("\"");
//                }
//                lineBuilder.append(",");

                //获取对应key的值
                lineBuilder.append(jsonObject.getString(key)).append(gt);
            }
            //去除多余的 gt
            lineBuilder.deleteCharAt(lineBuilder.length() - 1);
            csvStr.append(lineBuilder).append("\n");
        }
        return csvStr.toString();
    }


    /***
     * 由JSONObject对象转为对应格式字符串
     * @param jsonObject JSONObject
     * @param gt 分隔符
     * @return 转化好的对应格式字符串
     * @author cwt
     */
    private static String analyzeJson2Xml(JSONObject jsonObject, String gt) {
        StringBuilder str = new StringBuilder();
        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
            String key = entry.getKey();
            String val = entry.getValue().toString();
            //拆解JSON成一个map，然后再不断拆解，直到只剩下一个键对一个值
            if (val.length() > 0 && val.charAt(0) == '{') {
                appendXml(str, key, gt, val, 1);
            } else if (val.length() > 0 && val.charAt(0) == '[') {
                JSONArray jsons = JSONArray.parseArray(val); //解析成数组
                for (int i = 0; i < jsons.size(); i++) {
                    JSONObject tempJsonObject = new JSONObject();
                    //这里为出现一个键多个值做准备
                    // java8不允许使用\s（匹配任意字符） 故使用 \x20*代替
                    String regex = "\"([^\"]+)\"\\x20*:\\x20*\"([^\"]+)\"";
                    if (Pattern.matches(regex, jsons.get(i).toString())) {
                        tempJsonObject.put(key, jsons.getJSONObject(i));
                        str.append(analyzeJson2Xml(tempJsonObject, gt + "\t"));
                    } else {
                        tempJsonObject.put(key, jsons.get(i));
                        str.append(analyzeJson2Xml(tempJsonObject, gt));
                    }
                }
            } else {
                appendXml(str, key, gt, val, 0);
            }
        }
        return str.toString();
    }

    private static String analyzeJson2Xml(JSONArray jsonArray, String gt) {
        StringBuilder str = new StringBuilder();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("Object", jsonArray.getJSONObject(i));
            str.append(analyzeJson2Xml(jsonObject, gt));
        }
        return str.toString();
    }

    /***
     *
     * @param str 原串
     * @param key 键
     * @param gt 分隔符
     * @param val 值
     * @param flag 是嵌套还是普通拼接
     * @author cwt
     */

    private static void appendXml(StringBuilder str, String key, String gt, String val, int flag) {
        key = key.replaceAll("[^\\w:_-]", "_");
        str.append(gt).append("<").append(key).append(">");
        if (flag == 0) {
            val = StringEscapeUtils.escapeXml10(val);
            str.append(val);
        } else {
            str.append("\n");
            str.append(analyzeJson2Xml(JSONObject.parseObject(val), gt + "\t"));
            str.append(gt);
        }
        str.append("</").append(key).append(">\n");
    }

    /***
     *实现JSON转YAML
     * @param url 文件地址
     * @return 返回转化完成的Yaml字符串
     * @author cwt
     */

    public static String json2Yaml(String url) {
        begin(url);
        String jsonString = FileUtils.readFileToString(url, "UTF-8");
        if (jsonString.startsWith("[")) { //区分数组、对象
            JSONArray jsonArray = JSONArray.parseArray(jsonString);
            jsonString = JSON.toJSONString(jsonArray);
        } else {
            JSONObject jsonObject = JSONObject.parseObject(jsonString);
            jsonString = JSON.toJSONString(jsonObject);
        }
        // 将JSON转换为YAML
        Yaml yaml = createYaml();
        return yaml.dump(yaml.load(jsonString));
    }

    private static Yaml createYaml() {
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); // 设置块样式，使YAML更易读
        return new Yaml(options);
    }
}